/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package semant.second_pass;

import java.util.ArrayList;
import semant.Env;
import symbol.ClassInfo;
import symbol.MethodInfo;
import symbol.Symbol;
import symbol.VarInfo;
import syntaxtree.Call;
import syntaxtree.Exp;
import syntaxtree.IdentifierType;
import syntaxtree.Type;
import syntaxtree.VisitorAdapter;
import util.List;

/**
 *
 * @author Thiago
 */
class FormalHandler extends VisitorAdapter{

    Env env;
    ClassInfo info;
    ClassInfo c_atual;
    MethodInfo method;

    private FormalHandler(Env e, ClassInfo c, ClassInfo ca, MethodInfo m) {
        env = e;
        info = c;
        c_atual = ca;
        method = m;
   }

    static void secondPass(Env e, ClassInfo c,ClassInfo ca, MethodInfo m, Exp node) {
        FormalHandler h = new FormalHandler(e, c,ca,m);
        node.accept(h);
    }

    @Override
    public void visit(Call node)
    {                            
        MethodInfo m = info.methods.get(Symbol.symbol(node.method.s));

        if(m.formals == null){
            if(node.actuals==null){
                return;
            }
            else{
                env.err.Error(node.object, new Object[]{
                    "Número de parâmetros inválido para chamada do método "+node.method.s+
                            " na classe "+ info.name,
                            "Esperado: 0",
                            "Encontrado: " + node.actuals.size()});
                return;
            }
        }
        else{
            if(node.actuals==null){
                env.err.Error(node.object, new Object[]{
                    "Número de parâmetros inválido para chamada do método "+node.method.s+
                            " na classe "+ info.name,
                            "Esperado: "+ m.formals.size(),
                            "Encontrado: 0"});
                return;
            }
        }
        if(node.actuals.size()!=m.formals.size()){
            env.err.Error(node.object, new Object[]{
                    "Número de parâmetros inválido para chamada do método "+node.method.s+
                            " na classe "+ info.name,
                            "Esperado: "+ m.formals.size(),
                            "Encontrado: "+node.actuals.size()});
                return;
        }
        int i = 0;
        List<Exp> para = node.actuals;
        for(List<VarInfo> atual = m.formals; atual!= null ; atual = atual.tail)
        {
            i++;
            if(atual.head.type.getClass() != ExpHandler.secondPass(env, c_atual, method,para.head).getClass())
            {
                env.err.Error(node.object, new Object[]{
            "Tipo Inválido no "+ String.valueOf(i) + "º parâmetro para chamada do método "+node.method.s+
                    " na classe "+ info.name,
                    "Esperado: "+ atual.head.type.toString(),
                    "Encontrado: " + ExpHandler.secondPass(env, c_atual, method,para.head).toString()});
            }
            else{
                if(atual.head.type instanceof IdentifierType)
                {
                    ClassInfo dest = env.classes.get(Symbol.symbol(((IdentifierType)atual.head.type).name));
                    ClassInfo source = env.classes.get(Symbol.symbol(((IdentifierType)ExpHandler.secondPass(env,c_atual, method,para.head)).name));
                    if(!Type.isCompatible(dest, source))
                    {
                    env.err.Error(node.object, new Object[]{
                    "Tipo Inválido no "+ String.valueOf(i) + "º parâmetro para chamada do método "+node.method.s+
                            " na classe "+ info.name,
                            "Esperado: "+dest.name,
                            "Encontrado: " + source.name});
                    }
                }
            }


            para = para.tail;
        }
    }

}
